home *** CD-ROM | disk | FTP | other *** search
/ ftp.qualcomm.com / 2014.06.ftp.qualcomm.com.tar / ftp.qualcomm.com / eudora / developers / emsapi / carbon_emsapi.sit.hqx / Macintosh API Support / rfc1847.c < prev    next >
Text File  |  2001-03-08  |  18KB  |  637 lines

  1. /* ======================================================================
  2.  
  3.     Functions to aid manipulation and parsing of MIME RFC1847 objects.
  4.  
  5.     Filename:            rfc1847.c
  6.     Last Edited:        March 7, 1997
  7.     Authors:            Scott Manjourides, Bob Fronabarger
  8.     Copyright:            1995, 1996 QUALCOMM Inc.
  9.     Technical support:    <emsapi-info@qualcomm.com>
  10. */
  11.  
  12. #include "emsapi-mac.h"
  13. #include "rfc822.h"
  14. #include "rfc1847.h"
  15. #include "mimetype.h"
  16. #include "copycat.h"
  17.  
  18.  
  19. static StringPtr kBoundaryParameterName = "\pboundary";
  20. static StringPtr kBoundaryPrefixSuffix = "\p=-=-=-=";
  21.  
  22. static void RFC1847_CreateInit(createStateHandle pState);
  23. static long RFC1847_ParseInit(parseStateHandle pState);
  24.  
  25.  
  26. /* =========================================================================
  27.  *  Allocates and returns a pointer to an initialized createState structure.
  28.  *
  29.  *  NOTE: The user of this function is responsible for properly
  30.  *        deleting the returned data by calling DeleteCreateState()
  31.  *        when the state data is no longer needed.
  32.  *
  33.  *  No arguments.
  34.  *
  35.  *  Returns handle to newly created createState structure. nil if error.
  36.  */
  37. createStateHandle NewCreateState(void)
  38. {
  39.     createStatePtr        p, *pH = nil;
  40.     
  41.     pH = (createStateHandle) NewHandle(sizeof(createState));
  42.     if (pH) {
  43.         HLock((Handle) pH);
  44.             p = *pH;
  45.             p->initialized = false;
  46.             p->stage = p->next_stage = p->afterout_stage = CSE_Fail;
  47.             p->current_part = 0;
  48.             p->hTmpBuf = Make_Buf();
  49.             p->hOutputBuf = nil;
  50.             p->boundaryStr[0] = 0;
  51.         HUnlock((Handle) pH);
  52.     }
  53.     return pH;
  54. }
  55.  
  56.  
  57. /* =========================================================================
  58.  *  Frees all memory within the state structure, including the structure
  59.  *  itself.
  60.  *
  61.  *  NOTE: The pointer argument should be assumed invalid after this call.
  62.  *
  63.  *  Args:
  64.  *    pState [IN] Pointer to the state structure to be deleted.
  65.  */
  66. void DeleteCreateState(createStateHandle p)
  67. {
  68.     if (p) {
  69.         Delete_Buf((**p).hTmpBuf);
  70.         DisposeHandle((Handle)p);
  71.     }
  72. }
  73.  
  74.  
  75. /* =========================================================================
  76.  *  Allocates and returns a pointer to an initialized parseState structure.
  77.  *
  78.  *  NOTE: The user of this function is responsible for properly
  79.  *        deleting the returned data by calling DeleteCreateState()
  80.  *        when the state data is no longer needed.
  81.  *
  82.  *  No arguments.
  83.  *
  84.  *  Returns pointer to newly created parseState structure. nil if error.
  85.  */
  86. parseStateHandle NewParseState()
  87. {
  88.     parseStatePtr        p, *pH;
  89.     
  90.     pH = (parseStateHandle) NewHandle(sizeof(parseState));
  91.     if (!pH)
  92.         return (nil);
  93.     
  94.     HLock((Handle)pH);
  95.         p = *pH;
  96.         p->initialized = false;
  97.         p->stage = p->next_stage = p->afterout_stage = PSE_Fail;
  98.         p->current_part = p->outputCount = p->afteroutSkip = p->leftSpanCount = 0;
  99.         p->hOutputBuf = p->hSearchBuf = nil;
  100.         p->hPrevBuf = Make_Buf();
  101.         p->hBoundaryBuf = Make_Buf();
  102.         p->hDblNewlineBuf = Make_Buf();
  103.         p->hNewlineBuf = Make_Buf();
  104.     HUnlock((Handle)pH);
  105.     return (pH);
  106. }
  107.  
  108.  
  109. /* =========================================================================
  110.  *  Frees all memory within the state structure, including the structure
  111.  *  itself.
  112.  *
  113.  *  NOTE: The pointer argument should be assumed invalid after this call.
  114.  *
  115.  *  Args:
  116.  *    pState [IN] Pointer to the state structure to be deleted.
  117.  */
  118. void DeleteParseState(parseStateHandle p)
  119. {
  120.     if (!p) {
  121.         Delete_Buf((**p).hPrevBuf);
  122.         Delete_Buf((**p).hBoundaryBuf);
  123.         Delete_Buf((**p).hDblNewlineBuf);
  124.         Delete_Buf((**p).hNewlineBuf);
  125.         DisposeHandle((Handle) p);
  126.     }
  127. }
  128.  
  129. #pragma mark -
  130. /* =========================================================================
  131.  *  Performs necessary initialization for RFC1847_Create().
  132.  *
  133.  *  Args:
  134.  *    pState [IN] Pointer to the state structure.
  135.  *
  136.  *  Return value: BOOLEAN indicating success.
  137.  */
  138. static void RFC1847_CreateInit(createStateHandle pState)
  139. {
  140.     Str31        numStr;
  141.     Str255        theStr;
  142.     short        n;
  143.  
  144.     CopyPP(kBoundaryPrefixSuffix, theStr);
  145.  
  146.     n = Random();
  147.     if (n < 0)
  148.         n = -n;
  149.     NumToString(n, numStr);
  150.     CatPP(numStr, theStr);
  151.  
  152.     n = Random();
  153.     if (n < 0)
  154.         n = -n;
  155.     NumToString(n, numStr);
  156.     CatPP(numStr, theStr);
  157.  
  158.     n = Random();
  159.     if (n < 0)
  160.         n = -n;
  161.     NumToString(n, numStr);
  162.     CatPP(numStr, theStr);
  163.  
  164.      CatPP(kBoundaryPrefixSuffix, theStr);
  165.      
  166.      CopyPP(theStr, (**pState).boundaryStr);
  167.  
  168.     (**pState).stage = CSE_Start;
  169.     (**pState).initialized = true;
  170. }
  171.  
  172.  
  173. /* =========================================================================
  174.  *  Creates RFC1847 MIME structure.
  175.  *
  176.  *  Args:
  177.  *    mimeHdl  [IN]     MIME content info, used to create the MIME headers.
  178.  *    pOutBuf  [OUT]    Output buffer (RFC1847 MIME structure).
  179.  *    pInPart1 [IN]     Input buffer used for first part.
  180.  *    pInPart2 [IN]     Input buffer used for second part.
  181.  *    pState   [IN/OUT] Pointer to state info, caller must preserve.
  182.  *
  183.  *  Return values:
  184.  *    RFC1847_COMPLETED   Input was sucessfully and completely parsed.
  185.  *    RFC1847_BUFFERFULL  The output buffer is full; input partially parsed.
  186.  *    RFC1847_FAIL        Parsing error.
  187.  */
  188. long RFC1847_Create(emsMIMEtypeH mimeHdl, BufTypeHandle pOutBuf,
  189.                    BufTypeHandle pInPart1, BufTypeHandle pInPart2, createStateHandle hState)
  190. {
  191.     Handle            hCT = nil;
  192.     createStatePtr    pState;
  193.     long            status = RFC1847_COMPLETED;
  194.     unsigned long    nLen, nOut;
  195.  
  196.     if (!(**hState).initialized)
  197.         RFC1847_CreateInit(hState);
  198.  
  199.     HLock((Handle) hState);
  200.     pState = *hState;
  201.     while (pState->stage != CSE_Done) {
  202.         switch (pState->stage) {
  203.             case CSE_Start:
  204.                 pState->stage = CSE_DoHeader; /* Just an entry point */
  205.                 break;
  206.  
  207.             case CSE_DoHeader:
  208.                 pState->stage = CSE_Fail; // If not changed, then something failed
  209.  
  210.                 if (mimeHdl && pState->boundaryStr) {
  211.                     /* Remove the boundary parameter from the MIME struct -- if it's there */
  212.                     RemoveMimeParameter(mimeHdl, kBoundaryParameterName);
  213.  
  214.                     /* Add the boundary to the MIME type struct */
  215.                     AddMimeParameter(mimeHdl, kBoundaryParameterName, pState->boundaryStr);
  216.                     hCT = StringMimeType(mimeHdl);
  217.                     /* Create an RFC822 Content-Type header line from the MIME struct*/
  218.                     if (hCT != nil) {
  219.                         EmptyBuf_Buf(pState->hTmpBuf);
  220.                         HandleCat_Buf(pState->hTmpBuf, hCT);    // Content-Type:
  221.                         StrCat_Buf(pState->hTmpBuf, "\r\n");
  222.                         ResetPos_Buf(pState->hTmpBuf);
  223.                         DisposeHandle(hCT);
  224.  
  225.                         pState->hOutputBuf = pState->hTmpBuf;
  226.                         pState->afterout_stage = CSE_DoBoundary;
  227.                         pState->stage = CSE_DoOutput;
  228.                     }
  229.                 }
  230.                 break;
  231.  
  232.             case CSE_DoBoundary:
  233.                 StrCpy_Buf(pState->hTmpBuf, "\p\r\n");
  234.                 StrCat_Buf(pState->hTmpBuf, "--");
  235.                 PtoCstr(pState->boundaryStr);
  236.                 StrCat_Buf(pState->hTmpBuf, (char*) pState->boundaryStr);
  237.                 CtoPstr((char*) pState->boundaryStr);
  238.  
  239.                 if ((pState->current_part) < 2) { /* End the header and first part */
  240.                     pState->current_part++;
  241.                     pState->afterout_stage = CSE_DoPart;
  242.                 }
  243.                 else { /* End of second part */
  244.                     StrCat_Buf(pState->hTmpBuf, "--");
  245.                     pState->afterout_stage = CSE_Done;
  246.                 }
  247.                 StrCat_Buf(pState->hTmpBuf, "\r\n");
  248.                 ResetPos_Buf(pState->hTmpBuf);
  249.  
  250.                 pState->stage = CSE_DoOutput;
  251.                 pState->hOutputBuf = pState->hTmpBuf;
  252.                 break;
  253.  
  254.             case CSE_DoPart:
  255.                 switch (pState->current_part) {
  256.                     case 1:        /* We're doing part 1 now */
  257.                         if (PosLen_Buf(pInPart1) > 0) {
  258.                             pState->stage = CSE_DoOutput;
  259.                             pState->hOutputBuf = pInPart1;
  260.                             pState->afterout_stage = pInPart2 ? CSE_DoBoundary : CSE_DoPart;
  261.                         }
  262.                         else {        /* pInPart1 is empty/completed/non-existant */
  263.                             if (pInPart2)
  264.                                 pState->stage = CSE_DoBoundary;
  265.                             else    /* !pInPart2 */
  266.                                 goto Exit; /* We've eaten all of part 1, and there is no part 2 */
  267.                         }
  268.                         break;
  269.  
  270.                     case 2:     /* We're doing part 2 now */
  271.                         if (PosLen_Buf(pInPart2) > 0) {
  272.                             pState->stage = CSE_DoOutput;
  273.                             pState->hOutputBuf = pInPart2;
  274.                             pState->afterout_stage = CSE_DoPart;
  275.                         }
  276.                         else {        /* pInPart1 is empty/completed/non-existant */
  277.                             if (pInPart2)
  278.                                 goto Exit; /* We've eaten all of part 2 */
  279.                             else    /* !pInPart2 */
  280.                                 pState->stage = CSE_DoBoundary;
  281.                         }
  282.                         break;
  283.                 }
  284.                 break;
  285.  
  286.             case CSE_DoOutput:
  287.                 if (pOutBuf) {
  288.                     nLen = PosLen_Buf(pState->hOutputBuf);
  289.                     nOut = BufIns_Buf(pOutBuf, pState->hOutputBuf);
  290.                     if (nOut < nLen) {        /* Anything left to output */
  291.                         status = RFC1847_BUFFERFULL;
  292.                         goto Exit;
  293.                     }
  294.                     pState->stage = pState->afterout_stage;
  295.                 }
  296.                 else {
  297.                     status = RFC1847_BUFFERFULL;
  298.                     goto Exit;
  299.                 }
  300.                 break;
  301.  
  302.             case CSE_Fail:
  303.                 status = RFC1847_FAIL;
  304.                 goto Exit;
  305.         } /* switch (stage) */
  306.     } /* while */
  307.  
  308. Exit:
  309.     HUnlock((Handle) hState);
  310.     return status;
  311. }
  312.  
  313.  
  314. /* =========================================================================
  315.  *  Performs necessary initialization for RFC1847_Parse().
  316.  *
  317.  *  Args:
  318.  *    hState [IN] Pointer to the state structure.
  319.  *
  320.  *  Return value: BOOLEAN indicating success.
  321.  */
  322. static long RFC1847_ParseInit(parseStateHandle hState)
  323. {
  324.     if (!hState)
  325.         return (false);
  326.  
  327.     StrCpy_Buf((**hState).hNewlineBuf, "\p\r\n");
  328.     ResetPos_Buf((**hState).hNewlineBuf);
  329.  
  330.     StrCpy_Buf((**hState).hDblNewlineBuf, "\p\r\n\r\n");
  331.     ResetPos_Buf((**hState).hDblNewlineBuf);
  332.  
  333.     (**hState).stage = PSE_Start;
  334.     (**hState).initialized = true;
  335.  
  336.     return (true);
  337. }
  338.  
  339.  
  340. /* =========================================================================
  341.  *  Parses RFC1847 MIME structure, returning MIME info and separated parts.
  342.  *
  343.  *  Args:
  344.  *    mimeHdl   [OUT]    Returns a pointer to a newly created emsMIMEtype.
  345.  *    pOutPart1 [OUT]    Output buffer, part 1.
  346.  *    pOutPart2 [OUT]    Output buffer, part 2.
  347.  *    pInBuf    [IN]     Input buffer containing full RFC1847 MIME structure.
  348.  *    hState    [IN/OUT] Pointer to state info, caller must preserve.
  349.  *
  350.  *  Return values:
  351.  *    RFC1847_COMPLETED   Input was sucessfully and completely parsed.
  352.  *    RFC1847_BUFFERFULL  The output buffer is full; input partially parsed.
  353.  *    RFC1847_FAIL        Parsing error.
  354.  */
  355. long RFC1847_Parse(emsMIMEtypeH *mimeHdl, BufTypeHandle pOutPart1,
  356.                   BufTypeHandle pOutPart2, BufTypeHandle pInBuf, parseStateHandle hState)
  357. {
  358.     Boolean            bForceJumpState = false;
  359.     Handle            cp;
  360.     unsigned long    nSkip, nRemain, nPrevLen, nOut;
  361.     long            status = RFC1847_COMPLETED;
  362.     Ptr                pHeader, bufP;
  363.     char            *pCT;
  364.     parseStatePtr    pState;
  365.     BufTypeHandle    p;
  366.  
  367.     HLock((Handle) hState);
  368.     pState = *hState;
  369.     if (!pState->initialized)
  370.         if (!RFC1847_ParseInit(hState))
  371.             pState->stage = PSE_Fail;
  372.  
  373.     while ((bForceJumpState) || (PosLen_Buf(pInBuf) > 0)) {
  374.         bForceJumpState = false;
  375.  
  376.         switch (pState->stage) {
  377.             case PSE_Start:            /* Just an entry point */
  378.                 pState->stage = PSE_SkipHeader;
  379.                 break;
  380.  
  381.             case PSE_SkipHeader:
  382.                 pState->stage = PSE_KeepUntil;
  383.                 pState->next_stage = PSE_ParseHeader;
  384.                 pState->hSearchBuf = pState->hDblNewlineBuf;
  385.                 break;
  386.  
  387.             case PSE_ParseHeader:    /* Do all the mimeHdl stuff */
  388.                 ResetPos_Buf(pState->hPrevBuf);
  389.                 nPrevLen = PosLen_Buf(pState->hPrevBuf);
  390.                 
  391.                 pHeader = NewPtr(nPrevLen + 1);    // gethandlepos_buf(pState->hPrevBuf);
  392.                 if (!pHeader) {
  393.                     pState->stage = PSE_Fail;
  394.                     bForceJumpState = true;
  395.                     continue;
  396.                 }
  397.                 
  398.                 bufP = GetPos_Buf(pState->hPrevBuf);
  399.                 BlockMoveData(bufP, pHeader, nPrevLen);
  400.                 *(pHeader + nPrevLen) = '\0';
  401.  
  402.                 pCT = RFC822_ExtractHeader(pHeader, "Content-Type:");
  403.                 DisposePtr(pHeader);
  404.                 if (!pCT) {
  405.                     pState->stage = PSE_Fail;
  406.                     bForceJumpState = TRUE;
  407.                     continue;
  408.                 }
  409.  
  410.                 *mimeHdl = ParseMakeMimeType(pCT);
  411.                 DisposePtr(pCT);
  412.  
  413.                 /* get boundary info */
  414.                 cp = GetMimeParameter(*mimeHdl, kBoundaryParameterName);
  415.                 if (!cp) {
  416.                     pState->stage = PSE_Fail;
  417.                     bForceJumpState = true;
  418.                     continue;
  419.                 }
  420.                 StrCpy_Buf(pState->hBoundaryBuf, "\p\r\n--");
  421.                 HandleCat_Buf(pState->hBoundaryBuf, cp);
  422.                 // DO NOT free() cp
  423.  
  424.                 ResetPos_Buf(pState->hBoundaryBuf);
  425.                 
  426.                 nSkip = SkipCount_Buf(pState->hPrevBuf, pState->hBoundaryBuf);
  427.                 nRemain = nPrevLen - nSkip;
  428.  
  429.                 pState->leftSpanCount = nRemain;
  430.                 Free_Buf(pState->hPrevBuf);
  431.                 pState->stage = PSE_SkipFirst;
  432.                 break;
  433.  
  434.             case PSE_SkipFirst:
  435.                 pState->stage = PSE_IgnoreUntil;
  436.                 pState->hSearchBuf = pState->hBoundaryBuf;
  437.                 pState->next_stage = PSE_PrePart;
  438.                 break;
  439.  
  440.             case PSE_PrePart:
  441.                 pState->stage = PSE_IgnoreUntil;
  442.                 pState->hSearchBuf = pState->hNewlineBuf;
  443.                 pState->next_stage = PSE_OutPart;
  444.                 break;
  445.  
  446.             case PSE_OutPart:
  447.                 pState->current_part++;
  448.                 if (pState->current_part <= 2) {
  449.                     pState->stage = PSE_OutputUntil;
  450.                     pState->hSearchBuf = pState->hBoundaryBuf;
  451.                     pState->next_stage = PSE_PrePart;
  452.                 }
  453.                 else
  454.                     pState->stage = PSE_Done;
  455.                 break;
  456.  
  457.             case PSE_Done:
  458.                 ResetPos_Buf(pInBuf);    // DelPos_Buf(pInBuf);
  459.                 goto Exit;                // break;
  460.  
  461.             case PSE_Fail:
  462.                 status = RFC1847_FAIL;
  463.                 goto Exit;
  464.  
  465.             /* ----- ----- */
  466.  
  467.             case PSE_KeepUntil:
  468.             case PSE_IgnoreUntil:
  469.             case PSE_OutputUntil:
  470.             {
  471.                 Boolean            bFound = false;
  472.                 unsigned long    nPrefixCount = 0, nAfterSkip = 0, nInLen, nSearchLen, nNewMatched;
  473.  
  474.                 ResetPos_Buf(pState->hSearchBuf);
  475.  
  476.                 nInLen = PosLen_Buf(pInBuf);
  477.                 nSearchLen = PosLen_Buf(pState->hSearchBuf);
  478.  
  479.                 /* Did we have a partial span at the end of last buffer? */
  480.                 if (pState->leftSpanCount > 0) {
  481.                     //unsigned long nRemainingCount = nSearchLen - (pState->leftSpanCount);
  482.  
  483.                     /* Check for completion of span */
  484.                     // If doesn't continue match, returns zero
  485.                     // otherwise returns number of chars of hSearchBuf that have been matched
  486.                     nNewMatched = CompleteCount_Buf(pInBuf, pState->hSearchBuf, pState->leftSpanCount);
  487.  
  488.                     if (nNewMatched == nSearchLen) {    /* complete match made */
  489.                         bFound = true;
  490.                         nPrefixCount = 0; /* No chars in this buffer are before the match */
  491.                         nAfterSkip = nSearchLen - (pState->leftSpanCount); /* Move buffer position to AFTER match */
  492.  
  493.                         pState->leftSpanCount = 0;
  494.                     }
  495.                     else if (nNewMatched == 0) {    /* match failed */
  496.                         /* need to 'do' pState->leftSpanCount of pState->hSearchBuf */
  497.                         switch (pState->stage) {
  498.                             case PSE_KeepUntil:
  499.                                 BufNCat_Buf(pState->hPrevBuf, pState->hSearchBuf, pState->leftSpanCount);
  500.                                 break;
  501.                             case PSE_IgnoreUntil:
  502.                                 /* Ignore -- do nothing */
  503.                                 break;
  504.                             case PSE_OutputUntil:
  505.                                 pState->hOutputBuf = pState->hSearchBuf;
  506.                                 pState->outputCount = pState->leftSpanCount;
  507.                                 pState->afterout_stage = pState->stage; /* Stay in same stage */
  508.                                 pState->stage = PSE_DoOutput;
  509.                                 break;
  510.                         }
  511.                         pState->leftSpanCount = 0;
  512.                         if (pState->stage == PSE_DoOutput) {
  513.                             bForceJumpState = true;
  514.                             continue;
  515.                         }
  516.                     }
  517.                     else {    /* Continued to match, but not completed yet -- */
  518.                             /* the input buffer is smaller than the hSearchBuf */
  519.                         // Remainder of pInBuf matches, so we need to gobble it
  520.                         ResetPos_Buf(pInBuf);    //    DelPos_Buf(pInBuf);
  521.                         pState->leftSpanCount = nNewMatched;
  522.                         continue; // We want to 'return', because we are done with input
  523.                     }
  524.                 }
  525.  
  526.                 ResetPos_Buf(pState->hSearchBuf);
  527.  
  528.                 if (!bFound) {
  529.                     if (pState->hSearchBuf) {    // nSearchLen?
  530.                         unsigned long    skip, remain;
  531.                         // Find match of hSearchBuf, either complete or end-spanning
  532.                         // return number of chars to skip before match
  533.                         skip = SkipCount_Buf(pInBuf, pState->hSearchBuf);
  534.                         remain = nInLen - skip;
  535.  
  536.                         if (remain > nSearchLen) {    /* Found 'complete' */
  537.                             bFound = true;
  538.                             nPrefixCount = skip;
  539.                             nAfterSkip = nSearchLen;
  540.                         }
  541.                         else {    /* Either not found or partial possible */
  542.                             nPrefixCount = skip;
  543.                             nAfterSkip = remain; /* Gobble up the remaining (known to match) */
  544.                             pState->leftSpanCount = remain;
  545.                         }
  546.                     }
  547.                     else {
  548.                         nPrefixCount = nInLen;
  549.                         nAfterSkip = 0;
  550.                     }
  551.                 }
  552.  
  553.                 ResetPos_Buf(pState->hSearchBuf);
  554.  
  555.                 if (bFound) {    /* Found */
  556.                     switch (pState->stage) {
  557.                         case PSE_KeepUntil:
  558.                             BufNCat_Buf(pState->hPrevBuf, pInBuf, nPrefixCount + nAfterSkip);
  559.                             pState->stage = pState->next_stage;
  560.                             break;
  561.                         case PSE_IgnoreUntil: /* Ignore -- do nothing */
  562.                             IncPos_Buf(pInBuf, nPrefixCount + nAfterSkip);
  563.                             pState->stage = pState->next_stage;
  564.                             break;
  565.                         case PSE_OutputUntil:
  566.                             pState->hOutputBuf = pInBuf;
  567.                             pState->outputCount = nPrefixCount;
  568.                             pState->afterout_stage = pState->next_stage;
  569.                             pState->afteroutSkip = nAfterSkip;
  570.                             pState->stage = PSE_DoOutput;
  571.                             break;
  572.                         default:
  573.                             pState->stage = PSE_Fail;
  574.                     }
  575.                 }
  576.                 else {    /* not found */
  577.                     switch (pState->stage) {
  578.                         case PSE_KeepUntil:
  579.                             BufNCat_Buf(pState->hPrevBuf, pInBuf, nPrefixCount + nAfterSkip);
  580.                             break;
  581.                         case PSE_IgnoreUntil: /* Ignore -- do nothing */
  582.                             IncPos_Buf(pInBuf, nPrefixCount + nAfterSkip);
  583.                             break;
  584.                         case PSE_OutputUntil:
  585.                             pState->hOutputBuf = pInBuf;
  586.                             pState->outputCount = nPrefixCount;
  587.                             pState->afterout_stage = pState->stage; /* Same stage */
  588.                             pState->afteroutSkip = nAfterSkip;
  589.                             pState->stage = PSE_DoOutput;
  590.                             break;
  591.                         default:
  592.                             pState->stage = PSE_Fail;
  593.                     }
  594.                 }
  595.             }
  596.             break;
  597.  
  598.             case PSE_DoOutput:
  599.                 // Need to distiguish between the two output paths
  600.                 p = nil;
  601.                 switch (pState->current_part) {
  602.                     case 1:
  603.                         p = pOutPart1;
  604.                         break;
  605.                     case 2:
  606.                         p = pOutPart2;
  607.                         break;
  608.                     default:
  609.                         pState->stage = PSE_Fail;
  610.                 }
  611.                 if (p) {
  612.                     nOut = BufNIns_Buf(p, pState->hOutputBuf, pState->outputCount);
  613.  
  614.                     // Need to check if not everything was outputted
  615.                     // If not -- buffer is full, adjust 'outputCount', return BUFFERFULL;
  616.                     pState->outputCount -= nOut;
  617.  
  618.                     if ((pState->outputCount) > 0) { /* Anything left to output */
  619.                         status = RFC1847_BUFFERFULL;
  620.                         goto Exit;
  621.                     }
  622.                     pState->stage = pState->afterout_stage;
  623.                     if (pState->afteroutSkip > 0)
  624.                         IncPos_Buf(pState->hOutputBuf, pState->afteroutSkip);
  625.                 }
  626.                 else {
  627.                     status = RFC1847_BUFFERFULL;    /* No output buffer */
  628.                     goto Exit;
  629.                 }
  630.                 break;
  631.         }
  632.     }
  633. Exit:
  634.     HUnlock((Handle) hState);
  635.     return status;
  636. }
  637.